package com.sagacity.framework.util;

import com.sagacity.framework.api.model.request.Criterion;
import com.sagacity.framework.api.model.request.GeneralConditions;
import com.sagacity.framework.api.model.request.GenericQueryBO;
import com.sagacity.framework.exception.AppException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class SearchUtil<T> {

    private final GenericQueryBO<T> genericQuery;

    private SearchUtil(){
        genericQuery = GenericQueryBO.<T>builder().build();
    }

    public static <T> SearchUtil<T> builder(){
        return new SearchUtil<>();
    }

    public GenericQueryBO<T> build(){
        return genericQuery;
    }

    /**
     * 等于
     */
    public SearchUtil<T> ne(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.NE.name(), fieldValue);
    }
    /**
     * 不等于
     */
    public SearchUtil<T> eq(String fieldName, Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.EQ.name(), fieldValue);
    }

    /**
     * 大于
     */
    public SearchUtil<T> gt(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.GT.name(), fieldValue);
    }
    /**
     * 大于等于
     */
    public SearchUtil<T> ge(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.GE.name(), fieldValue);
    }
    /**
     * 小于
     */
    public SearchUtil<T> lt(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.LT.name(), fieldValue);
    }
    /**
     * 小于等于
     */
    public SearchUtil<T> le(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.LE.name(), fieldValue);
    }

    /**
     * 小于等于
     */
    public SearchUtil<T> between(String fieldName,Object smallValue,Object largeValue){
        // 将两个值合并
        List<Object> fieldValList = Arrays.asList(smallValue,largeValue);
        return criterion(fieldName,Criterion.ConditionEnum.BETWEEN.name(),fieldValList);
    }

    /**
     * 包含：两边%
     */
    public SearchUtil<T> like(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.LIKE.name(), fieldValue);
    }

    /**
     * 左包含：右边%，例子：abc%
     */
    public SearchUtil<T> leftLike(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.LEFT_LIKE.name(), fieldValue);
    }

    /**
     * 右包含：左边%，例子：%abc
     */
    public SearchUtil<T> rightLike(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.RIGHT_LIKE.name(), fieldValue);
    }

    /**
     * 不包含：两边%，例子：%abc%
     */
    public SearchUtil<T> notLike(String fieldName,Object fieldValue){
        return criterion(fieldName,Criterion.ConditionEnum.NOT_LIKE.name(), fieldValue);
    }

    /**
     * 多值匹配，例子：IN('20','45345')
     */
    public SearchUtil<T> in(String fieldName,Object ...fieldValue){
        List<Object> valueList = Arrays.asList(fieldValue);
        return criterion(fieldName,Criterion.ConditionEnum.IN.name(), valueList);
    }
    /**
     * 多值匹配，例子：IN('20','45345')
     */
    public SearchUtil<T> notIn(String fieldName,Object ...fieldValue){
        List<Object> valueList = Arrays.asList(fieldValue);
        return criterion(fieldName,Criterion.ConditionEnum.NOT_IN.name(), valueList);
    }

    public SearchUtil<T> or() {
        return connect(Criterion.ConnectEnum.OR.getConnect());
    }

    public SearchUtil<T> and() {
        return connect(Criterion.ConnectEnum.AND.getConnect());
    }

    public SearchUtil<T> isNull(String fieldName) {
        return criterion(fieldName,Criterion.ConditionEnum.IS_NULL.name(),null);
    }

    public SearchUtil<T> isNotNull(String fieldName) {
        return criterion(fieldName,Criterion.ConditionEnum.IS_NOT_NULL.name(),null);
    }

    public SearchUtil<T> pageNum(int pageNum) {
        genericQuery.setPageNum(pageNum);
        return this;
    }

    public SearchUtil<T> pageSize(int pageSize) {
        genericQuery.setPageSize(pageSize);
        return this;
    }

    public SearchUtil<T> page(int pageNum,int pageSize) {
        genericQuery.setPageNum(pageNum);
        genericQuery.setPageSize(pageSize);
        return this;
    }


    /**
     * 仅需查询的字段,自动驼峰转下划线 如："id","createBy","create_date"
     */
    public SearchUtil<T> includes(String ...includes) {
        genericQuery.setIncludes(Arrays.asList(includes));
        return this;
    }


    public SearchUtil<T> frontBracket() {
        return bracket(Criterion.BracketEnum.FRONT.getBracket());
    }

    public SearchUtil<T> afterBracket() {
        return bracket(Criterion.BracketEnum.AFTER.getBracket());
    }


    private SearchUtil<T> bracket(String bracket) {
        return criterion(null,null,null,bracket);
    }


    private SearchUtil<T> connect(String connect) {
        // 初始化
        GeneralConditions conditions = genericQuery.getConditions();
        if (conditions == null) {
            throw new AppException(String.format("%s使用非法", connect));
        }
        List<Criterion> criteria = conditions.getCriteria();
        if (CollectionUtil.isEmpty(criteria)) {
            throw new AppException(String.format("%s使用非法", connect));
        }

        // 第一条，无需加任何关联
        // 当前最后一条
        Criterion currLast
                = criteria.get(criteria.size() - 1);

        currLast.setConnect(connect);

        return this;
    }

    private SearchUtil<T> criterion(String fieldName, String condition, Object fieldValue,String bracket) {
        // 初始化
        initGeneralConditions();
        // 条件列表
        List<Criterion> criteria = genericQuery.getConditions().getCriteria();
        Criterion criterion = null;
        // 第一条，无需加任何关联
        if (criteria.size() != 0) {
            // 当前最后一条
            Criterion currLast
                    = criteria.get(criteria.size() - 1);
            // 若关联条件为空，则默认补充条件为AND
            if(StringUtil.isBlank(currLast.getConnect())){
                currLast.setConnect(Criterion.ConnectEnum.AND.getConnect());
            }

            // 最后一条若只是之前拼接括号，则当前需要补充值
//            if(StringUtil.isNotBlank(currLast.getPrefix()) &&
//                    (StringUtil.isAnyBlank(currLast.getFieldName(),currLast.getCondition()) || currLast.getFieldValue() == null)){
//                currLast.setFieldName(fieldName);
//                currLast.setCondition(condition);
//                currLast.setFieldValue(fieldValue);
//                criterion = currLast;
//            }

            // 最后一条若括号后缀为空，且有传入，则需要处理
            if(Criterion.BracketEnum.FRONT.getBracket().equals(currLast.getPrefix())
                    && StringUtil.isAllBlank(currLast.getFieldName(),currLast.getCondition())
                    && currLast.getFieldValue() == null){
                currLast.setFieldName(fieldName);
                currLast.setCondition(condition);
                currLast.setFieldValue(fieldValue);
                criterion = currLast;
            }else if(Criterion.BracketEnum.AFTER.getBracket().equals(bracket)
                    && StringUtil.isNoneBlank(currLast.getFieldName(),currLast.getCondition())
                    && currLast.getFieldValue() != null){
                currLast.setSuffix(bracket);
                criterion = currLast;
            }




        }
        if(criterion == null){
            // 字段条件
            criterion = Criterion.builder()
                    .fieldName(fieldName)
                    .condition(condition)
                    .fieldValue(fieldValue)
                    .prefix(bracket)
                    .build();
            criteria.add(criterion);
        }


        // 设置值
        genericQuery.getConditions().setCriteria(criteria);
        return this;
    }

    private SearchUtil<T> criterion(String fieldName, String condition, Object fieldValue) {
        return criterion(fieldName,condition,fieldValue,null);
    }

    private void initGeneralConditions(){
        // 初始化
        GeneralConditions conditions = genericQuery.getConditions();
        if(conditions == null){
            conditions = new GeneralConditions();
        }
        List<Criterion> criteria = conditions.getCriteria();
        if(CollectionUtil.isEmpty(criteria)){
            criteria = new ArrayList<>();
        }
        conditions.setCriteria(criteria);
        genericQuery.setConditions(conditions);
    }


//    /**
//     *  EQ("=","等于"),
//     *         NE("<>","不等于"),
//     *         GT(">","大于"),
//     *         GE(">=","大于等于"),
//     *         LT("<","小于"),
//     *         LE("<=","小于等于"),
//     *         BETWEEN("BETWEEN","在...和...之间"),
//     *         LIKE("LIKE","包含：两边%"),
//     *         LEFTLIKE("LIKE","左包含：右边%"),
//     *         RIGHTLIKE("LIKE","右包含：左边%"),
//     *         NOTLIKE("NOT LIKE","不包含：两边%"),
//     *         LEFTNOTLIKE("NOT LIKE","左不包含：右边%"),5744+/
//     *         RIGHTNOTLIKE("NOT LIKE","右不包含：左边%"),
//     *         IN("IN","多值匹配"),
//     *         NOTIN("NOT IN","不是对应的多只匹配"), ;
//     * @param args
//     */
//    public static void main(String[] args) {
//        GenericQueryBO<Map<String, String>> build = SearchUtil.<Map<String, String>>builder()
//                .eq("orderSn", "12019218210391")
////                .ne("traceId","5968c89e436d1719")
//                // .gt("id",123780589603024006L)
//                // .ge("id",123780589603024006L)
//                // .lt("id",123780725479952002L)
//                // .le("id",123780725479952002L)
//                // .like("traceId","3fa3")
//                // .leftLike("traceId","f420d")
////                .notIn("traceId","f420d73cd91b83d0")
////                .between("createTime","2021-10-01","2024-10-01")
////                .frontBracket()
////                    .eq("id",123780725479952002L)
////                .or().eq("id",123780727202416003L)
////                .afterBracket()
//                .isNull("id")
//                // IN
////                .in("id",123780707092528001L,123780727202416003L)
//
//                .build();
//        System.out.println(JsonUtil.toJson(build.getConditions()));
//    }

}
